//
//  ISSafetyAlarmMamanger.m
//  iPhoneSafety
//
//  Created by dl on 2019/1/3.
//  Copyright © 2019 com.li.ding. All rights reserved.
//

#import "ISSafetyAlarmMamanger.h"
#import <CoreMotion/CoreMotion.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <MBProgressHUD/MBProgressHUD.h>
#import <MediaPlayer/MediaPlayer.h>
#import "ISRingServer.h"

NSString * const kISSafetyAlarmStateDidChangeNotification = @"kISSafetyAlarmStateDidChangeNotification";
NSString * const kISSafetyAlarmStateAlarmingNotification = @"kISSafetyAlarmStateAlarmingNotification";

@interface ISSafetyAlarmMamanger()
@property (nonatomic, assign, readwrite) ISSafetyAlarmStrategy strategy;

@property (nonatomic, assign, readwrite) ISSafetyAlarmPocketState alarmPocketState;
@property (nonatomic, assign, readwrite) ISSafetyAlarmDeskState alarmDeskState;
@property (nonatomic, assign, readwrite) ISSafetyAlarmChargingState alarmChargingState;
@property (nonatomic, assign, readwrite) ISSafetyAlarmAirplanState alarmAirplanState;
@property (nonatomic, assign, readwrite) ISSafetyAlarmHeadsetState alarmHeadsetState;

@property (nonatomic, strong) CMMotionManager *motionManager;
@property (nonatomic, strong) CTTelephonyNetworkInfo *networkInfo;

@property (nonatomic, strong) NSTimer *deskStableTimer;

@property (nonatomic, strong) id radiosPreferences;

@property (nonatomic, strong, readwrite) NSMutableDictionary *stategyOnDict;

@property (nonatomic, strong) MPVolumeView *volumeView;
@end

@implementation ISSafetyAlarmMamanger

NW_SINGLETON_INSTANCE_METHOD_IMPLEMENTATION

- (instancetype)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(didPocketAlarmWithNoti:)
                                                     name:UIDeviceProximityStateDidChangeNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(audioRouteDidChangeNoti:)
                                                     name:AVAudioSessionRouteChangeNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(batteryStateDidChangeNoti:)
                                                     name:UIDeviceBatteryStateDidChangeNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(systemDiVolumedChangeNoti:)
                                                     name:@"AVSystemController_SystemVolumeDidChangeNotification"
                                                   object:nil];
        
        self.motionManager = [[CMMotionManager alloc] init];
        self.motionManager.accelerometerUpdateInterval = 0.1;
        
        self.networkInfo = [[CTTelephonyNetworkInfo alloc] init];
        
        self.radiosPreferences = [[NSClassFromString(@"RadiosPreferences") alloc] init];
        [self.radiosPreferences setDelegate:self];
        
        NSArray *keypaths = @[@"alarmPocketState", @"alarmDeskState", @"alarmChargingState", @"alarmAirplanState", @"alarmHeadsetState"];
        @weakify(self)
        [self.KVOController observe:self keyPaths:keypaths options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:kISSafetyAlarmStateDidChangeNotification object:nil];
            });
        }];
    }
    return self;
}

- (void) systemDiVolumedChangeNoti:(NSNotification *)noti {
    if (self.isAlarming) {
        [self resetSystemVlume];
    }
}

- (void) resetSystemVlume {
    if (!self.volumeView) {
        self.volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        self.volumeView.hidden = YES;
        [[UIApplication sharedApplication].keyWindow addSubview:self.volumeView];
    }
    UISlider* volumeViewSlider = nil;
    for (UIView *view in [self.volumeView subviews]){
        if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
            volumeViewSlider = (UISlider*)view;
            break;
        }
    }
    self.volumeView.showsVolumeSlider = YES;
    [volumeViewSlider setValue:[ISRingServer shareInstance].config.voice animated:NO];
    [volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];
    [self.volumeView sizeToFit];
}

- (BOOL)isAlarming {
    return self.alarmPocketState == ISSafetyAlarmPocketStateAlarming
            || self.alarmDeskState == ISSafetyAlarmDeskStateAlarming
            || self.alarmChargingState == ISSafetyAlarmChargingStateAlarming
            || self.alarmAirplanState == ISSafetyAlarmAirplanStateAlarming
            || self.alarmHeadsetState == ISSafetyAlarmHeadsetStateAlarming;
}

- (BOOL)isAllClosed {
    return self.alarmPocketState == ISSafetyAlarmPocketStateClosed
            && self.alarmDeskState == ISSafetyAlarmDeskStateClosed
            && self.alarmChargingState == ISSafetyAlarmChargingStateClosed
            && self.alarmAirplanState == ISSafetyAlarmAirplanStateClosed
            && self.alarmHeadsetState == ISSafetyAlarmHeadsetStateClosed;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void) onOrCloseStrategy:(ISSafetyAlarmStrategy)strategy on:(BOOL)isOn {
    self.stategyOnDict[[@(strategy) stringValue]] = @(isOn);
    [[NSUserDefaults standardUserDefaults] setObject:self.stategyOnDict forKey:@"kStrategyOnDict"];
}

- (BOOL)onOrCloseWithStrategy:(ISSafetyAlarmStrategy)strategy {
    return [self.stategyOnDict[[@(strategy) stringValue]] boolValue];
}

- (BOOL) startMonitoringWithStrategyStatus {
    ISSafetyAlarmStrategy strategy = ISSafetyAlarmStrategyNone;
    
    if ([self onOrCloseWithStrategy:ISSafetyAlarmStrategyPocket]) {
        strategy = strategy | ISSafetyAlarmStrategyPocket;
    }
    
    if ([self onOrCloseWithStrategy:ISSafetyAlarmStrategyDesk]) {
        strategy = strategy | ISSafetyAlarmStrategyDesk;
    }
    
    if ([self onOrCloseWithStrategy:ISSafetyAlarmStrategyCharging]) {
        strategy = strategy | ISSafetyAlarmStrategyCharging;
    }
    
    if ([self onOrCloseWithStrategy:ISSafetyAlarmStrategyHeadset]) {
        strategy = strategy | ISSafetyAlarmStrategyHeadset;
    }
    
    if ([self onOrCloseWithStrategy:ISSafetyAlarmStrategyAirplan]) {
        strategy = strategy | ISSafetyAlarmStrategyAirplan;
    }
    
    if (strategy == ISSafetyAlarmStrategyNone) {
        [NWToast showToast:@"请选择模式"];
        return NO;
    }
    
    [self startMonitoringWithStrategy:strategy];
    return YES;
}

- (void) startMonitoringWithStrategy:(ISSafetyAlarmStrategy)strategy {
    self.strategy = strategy;
    
    [self switchPocketAlarmEnable:(self.strategy & ISSafetyAlarmStrategyPocket)];
    [self switchDeskAlarmEnable:(self.strategy & ISSafetyAlarmStrategyDesk)];
    [self switchChargingAlarmEnable:(self.strategy & ISSafetyAlarmStrategyCharging)];
    [self switchHeadsetAlarmEnable:(self.strategy & ISSafetyAlarmStrategyHeadset)];
    [self switchAirplanAlarmEnable:(self.strategy & ISSafetyAlarmStrategyAirplan)];
}

- (void) stop {
    [self switchPocketAlarmEnable:NO];
    [self switchDeskAlarmEnable:NO];
    [self switchChargingAlarmEnable:NO];
    [self switchHeadsetAlarmEnable:NO];
    [self switchAirplanAlarmEnable:NO];
}

#pragma mark - strategy -> pocket
- (void) switchPocketAlarmEnable:(BOOL)enable {
    [UIDevice currentDevice].proximityMonitoringEnabled = enable;
    self.alarmPocketState = enable ? ISSafetyAlarmPocketStatePrepare : ISSafetyAlarmPocketStateClosed;
}

- (void) didPocketAlarmWithNoti:(NSNotification *)noti {
    if ([UIDevice currentDevice].proximityState) {
        NSLog(@"有物品靠近");
        self.alarmPocketState = ISSafetyAlarmPocketStateReady;
    } else {
        NSLog(@"有物品离开");
        self.alarmPocketState = ISSafetyAlarmPocketStateAlarming;
        [self didPocketAlarm];
    }
}

#pragma mark - strategy -> pocket
- (void) switchDeskAlarmEnable:(BOOL)enable {
    if (enable && !self.motionManager.accelerometerActive) {
        self.alarmDeskState = ISSafetyAlarmDeskStatePrepare;
        [self stopDeskStableTimer];
        NSLog(@"prepare to start desk mode");
        @weakify(self)
        [self.motionManager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init] withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
            @strongify(self)
            CGFloat x = accelerometerData.acceleration.x;
            CGFloat y = accelerometerData.acceleration.y;
            CGFloat z = accelerometerData.acceleration.z;
            
            if (fabs(x) < 0.05 && fabs(y) < 0.05 && 1.f - fabs(z) < 0.05) {
                if (self.alarmDeskState == ISSafetyAlarmDeskStatePrepare && ![self.deskStableTimer isValid]) {
                    [self startDeskStableTimer];
                }
            } else {
                if (self.alarmDeskState == ISSafetyAlarmDeskStateReady) {
                    self.alarmDeskState = ISSafetyAlarmDeskStateAlarming;
                    [self didDeskAlarm];
                    NSLog(@"desk mode alarm");
                } else {
                    if (self.alarmDeskState != ISSafetyAlarmDeskStatePrepare) {
                        self.alarmDeskState = ISSafetyAlarmDeskStatePrepare;
                    }
                }
                [self stopDeskStableTimer];
            }
        }];
    } else if(!enable) {
        NSLog(@"stop desk mode");
        [self.motionManager stopAccelerometerUpdates];
        [self stopDeskStableTimer];
        if (self.alarmDeskState != ISSafetyAlarmDeskStateClosed) {
            self.alarmDeskState = ISSafetyAlarmDeskStateClosed;
        }
    }
}

- (void) startDeskStableTimer {
    NSLog(@"desk mode start timer");
    [self stopDeskStableTimer];
    @weakify(self)
    self.deskStableTimer = [NSTimer bk_timerWithTimeInterval:1.f block:^(NSTimer *timer) {
        @strongify(self)
        self.alarmDeskState = ISSafetyAlarmDeskStateReady;
        NSLog(@"desk mode ready");
    } repeats:NO];
    [[NSRunLoop mainRunLoop] addTimer:self.deskStableTimer forMode:NSRunLoopCommonModes];
}

- (void) stopDeskStableTimer {
    if ([self.deskStableTimer isValid]) {
        [self.deskStableTimer invalidate];
        self.deskStableTimer = nil;
        NSLog(@"desk mode stop timer");
    }
}

#pragma mark - strategy -> Charging
- (void) switchChargingAlarmEnable:(BOOL)enable {
    [UIDevice currentDevice].batteryMonitoringEnabled = enable;
    if (enable) {
        UIDeviceBatteryState state = [UIDevice currentDevice].batteryState;
        if (state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull) {
            self.alarmChargingState = ISSafetyAlarmChargingStateReady;
        } else {
            self.alarmChargingState = ISSafetyAlarmChargingStatePrepare;
        }
    } else {
        self.alarmChargingState = ISSafetyAlarmChargingStateClosed;
    }
}

- (void) batteryStateDidChangeNoti:(NSNotification *)noti {
    UIDeviceBatteryState state = [UIDevice currentDevice].batteryState;
    if (state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull) {
        if (self.alarmChargingState == ISSafetyAlarmChargingStatePrepare) {
            self.alarmChargingState = ISSafetyAlarmChargingStateReady;
            NSLog(@"ready to charging moitoring");
        }
    } else if(state == UIDeviceBatteryStateUnplugged && self.alarmChargingState == ISSafetyAlarmChargingStateReady) {
        self.alarmChargingState = ISSafetyAlarmChargingStateAlarming;
        NSLog(@"charging moitoring alarming");
        [self didChargingAlarm];
    }
}

#pragma mark - strategy -> airplan
- (void) switchAirplanAlarmEnable:(BOOL)enable {
    self.alarmAirplanState = enable ? ISSafetyAlarmAirplanStateReady : ISSafetyAlarmAirplanStateClosed;
}

#pragma mark - RadiosPreferencesDelegate
-(void)airplaneModeChanged {
    BOOL airplanModeIsOn = [[self.radiosPreferences valueForKeyPath:@"airplaneMode"] boolValue];
    NSLog(@"airplan state: %@", @(airplanModeIsOn));
    if (self.alarmAirplanState == ISSafetyAlarmAirplanStateReady && airplanModeIsOn) {
        self.alarmAirplanState = ISSafetyAlarmAirplanStateAlarming;
        [self didAirplanAlarm];
    }
}

#pragma mark - strategy -> Headset
- (void) switchHeadsetAlarmEnable:(BOOL)enable {
    [[AVAudioSession sharedInstance] setActive:enable error:nil];
    if (!enable) {
        self.alarmHeadsetState = ISSafetyAlarmHeadsetStateClosed;
    } else {
        BOOL isNowHeadsetOn = [self isHeadsetPluggedIn];
        self.alarmHeadsetState = isNowHeadsetOn ? ISSafetyAlarmHeadsetStateReady : ISSafetyAlarmHeadsetStatePrepare;
    }
}

- (BOOL)isHeadsetPluggedIn {
    AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
    for (AVAudioSessionPortDescription* desc in [route outputs]) {
        if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones])
            return YES;
    }
    return NO;
}

- (void) audioRouteDidChangeNoti:(NSNotification*)noti {
    NSDictionary *interuptionDict = noti.userInfo;
    NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
    switch (routeChangeReason) {
        case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
            NSLog(@"耳机插入");
            self.alarmHeadsetState = ISSafetyAlarmHeadsetStateReady;
            break;
        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
            NSLog(@"耳机拔出，停止播放操作");
            self.alarmHeadsetState = ISSafetyAlarmHeadsetStateAlarming;
            [self didHeadsetAlarm];
            break;
        case AVAudioSessionRouteChangeReasonCategoryChange:
            break;
    }
}

#pragma mark - desk alarm
- (void) didPocketAlarm {
    [self doAlarmWithStrategy:ISSafetyAlarmStrategyPocket];
}

- (void) didDeskAlarm {
    [self doAlarmWithStrategy:ISSafetyAlarmStrategyDesk];
}

- (void) didChargingAlarm {
    [self doAlarmWithStrategy:ISSafetyAlarmStrategyCharging];
}

- (void) didAirplanAlarm {
    [self doAlarmWithStrategy:ISSafetyAlarmStrategyAirplan];
}

- (void) didHeadsetAlarm {
    [self doAlarmWithStrategy:ISSafetyAlarmStrategyHeadset];
}

- (void) doAlarmWithStrategy:(ISSafetyAlarmStrategy)strategy {
    [[NSNotificationCenter defaultCenter] postNotificationName:kISSafetyAlarmStateAlarmingNotification object:@(strategy)];
    [self resetSystemVlume];
}

#pragma mark - set & get

- (NSMutableDictionary *)stategyOnDict {
    if (!_stategyOnDict) {
        _stategyOnDict = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] objectForKey:@"kStrategyOnDict"]];
    }
    if (!_stategyOnDict) {
        _stategyOnDict = @{}.mutableCopy;
    }
    return _stategyOnDict;
}
@end
